package com.njmaomao.gj.pyot.common;

import static java.util.stream.Collectors.toList;

import java.lang.reflect.Type;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import org.apache.commons.beanutils.PropertyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

/**
 * 类功能描述: Json工具类
 *
 * @author hh
 * @version 1.0
 * @createDate 2016年8月4日 上午10:20:59
 */
public abstract class Utils {

    protected static final Logger log = LoggerFactory.getLogger(Utils.class);

    //去掉了01Olo等容易混淆的字符
    private static String AB = "23456789ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz";

    private static final SecureRandom rnd = new SecureRandom();

    public static final String ENV_CONF = "spring.profiles.active";

    public static final String DEV = "dev";
    public static final String TEST = "test";

    private static Gson gson = new Gson();
//    private static final Gson gson = new GsonBuilder().registerTypeAdapterFactory(HibernateProxyTypeAdapter.FACTORY).create();

    public static final String toJson(Object o) {
        return gson.toJson(o);
    }

    public static final String toJson(Object o, Type type) {
        return gson.toJson(o, type);
    }

    public static final <T> T toObj(String jsonString, Class<T> clazz) {
        return gson.fromJson(jsonString, clazz);
    }

    public static final <T> T toObj(String jsonString, Type type) {
        return gson.fromJson(jsonString, type);
    }

    public static String getSeqNo() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * List 元素转换
     *
     * @param sources
     * @param function
     * @return
     */
    public static <T, R> List<R> qmap(Collection<T> sources, Function<? super T, ? extends R> function) {
        return Optional.ofNullable(sources).orElse(new ArrayList<>(0)).stream().map(function).collect(toList());
    }

    /**
     * List 元素过滤后转换
     *
     * @param sources
     * @param function
     * @param filter
     * @return
     */
    public static <T, R> List<R> qmap(Collection<T> sources, Function<? super T, ? extends R> function, Predicate<? super T> filter) {
        return Optional.ofNullable(sources).orElse(new ArrayList<>(0)).stream().filter(filter).map(function).collect(toList());
    }

    /**
     * Map value元素转换
     * @param fromMap
     * @param valMapFunc
     * @param <K>
     * @param <V1>
     * @param <V2>
     * @return
     */
    public static <K, V1, V2> Map<K, V2> qmap(Map<K, V1> fromMap, Function<? super V1, ? extends V2> valMapFunc) {
        return Optional.ofNullable(fromMap)
                .orElse(new HashMap<>())
                .entrySet()
                .stream()
                .collect(Collectors.toMap(Map.Entry::getKey, e -> valMapFunc.apply(e.getValue())));
    }

    public static String randomString(int len){
        int length = AB.length();
        StringBuilder sb = new StringBuilder(len);
        for( int i = 0; i < len; i++ ) {
            sb.append(AB.charAt(rnd.nextInt(length)));
        }
        return sb.toString();
    }

    public static <T> Map<T, T> newHashMap(T... parameters) {
        Map<T, T> result = new HashMap<>();
        for (int i = 0; i < parameters.length; i += 2) {
            result.put(parameters[i], parameters[i + 1]);
        }
        return result;
    }

    public static <T> Optional<T> extractProperty(Object bean, String property) {
        T propertyVal = null;
        try {
            propertyVal = (T) PropertyUtils.getProperty(bean, property);
        } catch (Exception e) {
            log.warn("extractProperty fail with bean:{}, property:{}, err: {}", bean.getClass(), property, e);
        }
        return Optional.ofNullable(propertyVal);
    }

    public static <T> T extractProperty(Object bean, String property, T defaultVal) {
        return (T) extractProperty(bean, property).orElse(defaultVal);
    }

    public static <T> T firstEffectiveVal(T defaultVal, Supplier<Optional<T>>... optsSplr) {
        return Arrays.asList(optsSplr).stream().map(Supplier::get).filter(Optional::isPresent).findFirst().orElse(Optional.ofNullable(defaultVal)).get();
    }

    public static <T> Optional<T> firstEffectiveVal(Supplier<Optional<T>>... optsSplr) {
        return Arrays.asList(optsSplr).stream().map(Supplier::get).filter(Optional::isPresent).findFirst().orElse(Optional.empty());
    }

    public static Map<String, String> toMap(Object bean) {
        return Utils.toObj(Utils.toJson(bean), new TypeToken<Map<String, String>>() { }.getType());
    }

    public static <T, V> List<T> map(List<Map<String, V>> records, Class<T> clazz){
        return records.stream().map(map -> Utils.toBean(map, clazz)).collect(Collectors.toList());
    }

    public static <T> T toBean(Map<String, ?> map, Class<T> tClass) {
        return Utils.toObj(Utils.toJson(map), tClass);
    }
    public static <T> T toBean(Object obj, Class<T> tClass) {
        return Utils.toObj(Utils.toJson(obj), tClass);
    }

    /*public static boolean isDev() {
        return System.getProperty(ENV_CONF).equals(DEV);
    }

    public static boolean isTest() {
        return System.getProperty(ENV_CONF).equals(TEST);
    }*/

}
